#pragma once

#include <list>
#include <mutex>
#include <vector>
#include <thread>
#include <condition_variable>
#include <memory>
#include <iostream>
#include <unistd.h>

#define THREAD_NUMBERS 10 // 默认线程数量
template <class T>
class thread_poll
{
private:
    void thread_handler()
    {
        while (true)
        {
            T task;
            // 互斥式的访问任务队列
            {
                std::unique_lock<std::mutex> lock(_mutex);
                while (_tq.empty())
                {
                    // 条件变量下阻塞
                    _cond.wait(lock);
                }
                pop(task);
            }
            task();// 执行任务时不需要互斥
            std::cout << std::this_thread::get_id() << "号线程执行任务..." << std::endl;
            sleep(1);
        }
    }

public:
    thread_poll()
    {}

    // 启动线程池
    void start()
    {
        int cnt = THREAD_NUMBERS;
        while(cnt--)
        {
            std::thread t(&thread_poll<T>::thread_handler,this);
            t.detach();
        }
    }

    void push(const T &t)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _tq.push_back(t);
        _cond.notify_all();
    }

    // 该方法已经在临界区中互斥式的访问了，所以该方法不需要加锁，否则造成死锁(临界区加一次，方法内右要加一次，就死锁了)
    void pop(T &out)
    {
        //std::unique_lock<std::mutex> lock(_mutex);
        if (!_tq.empty())
        {
            out = _tq.front();
            _tq.pop_front();
        }
    }
protected:
    std::vector<std::thread> _threadVec;
    std::condition_variable _cond;
    std::mutex _mutex;
    std::list<T> _tq; // 用链表来模拟队列，原因是比queue的灵活性更高
};